#ifndef __WATCHER_H__
#define __WATCHER_H__

#include "base/Entity.h"
#include "base/Simulator.h"
#include "util/Pool.h"

class Watcher : public Entity {
  public:
    NEW_DELETE_OPERATORS_INLINE_H(Watcher,Entity);
    Watcher (Time ws, VA wa) : 
        Entity("Watcher", CLOCK_FIRST), 
        watcherSimclock(ws),
        watcherAddress(ADDR_UINT32STAR(wa)),
        watcherValue(0)
    {
    }
    Watcher (Time ws, void* wa) : 
        Entity("Watcher", CLOCK_FIRST), 
        watcherSimclock(ws),
        watcherAddress((uint32*)wa),
        watcherValue(0)
    {
    }

    ~Watcher () {}

    void tick () {
        if (watcherSimclock == 0) {
            // no simclock specified yet
            return;
        }
        if (watcherAddress == NULL) {
            // no address specified yet
            return;
        }
        Time simclock = global_sim->getSimclock();
        if (simclock < watcherSimclock) {
            // its not time to watch yet
            return;
        }
        uint32 value = *watcherAddress;
        if (watcherValue == value) {
            // value has not changed yet
            return;
        }

        // value changed
        
        // record new value
        watcherValue = value;
        // log it
        Log->w("[Watcher] %lld *%p=%x(%d)\n",
               simclock,
               watcherAddress,
               watcherValue,
               watcherValue);
    }

    void setWatcherSimclock (Time ws) {
        watcherSimclock = ws;
    }

    void setWatcherAddress (VA wa) {
        watcherAddress = ADDR_UINT32STAR(wa);
    }
    void setWatcherAddress (void* wa) {
        watcherAddress = (uint32*)wa;
    }

  private:
    /**
       only watch address after the watcherSimclock. Typically you
       need to wait until some point in the simulation when the
       address is actually valid. a zero value disables the Watcher.
     */
    Time watcherSimclock;
    
    /** 
        The address to watch for changes. A NULL address disables the
        Watcher
     */
    uint32* watcherAddress;

    /** 
        The last seen value, starts at zero, which may cause one
        spurious message.
     */
    uint32 watcherValue;
    
};

#endif
